home *** CD-ROM | disk | FTP | other *** search
Text File | 1996-07-03 | 6.9 KB | 234 lines | [TEXT/R*ch] |
- (* FileSys -- 1995-06-16, 1995-09-25 *)
-
- local
- #ifdef unix
- val defaulttempdir = "/tmp";
- #endif
- #ifdef msdos
- val defaulttempdir = "c:\\tmp";
- #endif
- #ifdef macintosh
- val defaulttempdir = ":";
- #endif
-
- (* The type of directory structures, as handled by the OS: *)
- prim_type dirstruct_;
-
- (* Primitives from runtime/sys.c -- raise Io on error *)
- prim_val chdir_ : string -> unit = 1 "sys_chdir";
- prim_val remove_ : string -> unit = 1 "sys_remove";
- prim_val rename_ : string -> string -> unit = 2 "sys_rename";
-
- (* Primitives from runtime/mosml.c -- raise Fail on error *)
- prim_val access_ : string -> int -> bool = 2 "sml_access";
- prim_val getdir_ : unit -> string = 1 "sml_getdir";
- prim_val isdir_ : string -> bool = 1 "sml_isdir";
- prim_val mkdir_ : string -> unit = 1 "sml_mkdir";
- prim_val mktemp_ : string -> string = 1 "sml_mktemp";
- prim_val modtime_ : string -> real = 1 "sml_modtime";
- prim_val rmdir_ : string -> unit = 1 "sml_rmdir";
- prim_val settime_ : string -> real -> unit = 2 "sml_settime";
-
- prim_val opendir_ : string -> dirstruct_ = 1 "sml_opendir";
- prim_val readdir_ : dirstruct_ -> string = 1 "sml_readdir";
- prim_val rewinddir_ : dirstruct_ -> unit = 1 "sml_rewinddir";
- prim_val closedir_ : dirstruct_ -> unit = 1 "sml_closedir";
-
- fun formatErr mlOp operand reason =
- "FileSys." ^ mlOp ^ " failed on \"" ^ operand ^ "\": " ^ reason ^ "\n"
-
- (* Raise SysErr from ML function *)
- fun raiseSysML mlOp operand reason =
- raise OS.SysErr (formatErr mlOp operand reason, NONE)
-
- (* Raise SysErr with OS specific explanation if errno <> 0 *)
- fun raiseSys mlOp operand reason =
- let prim_val errno_ : unit -> int = 1 "sml_errno";
- prim_val errormsg_ : int -> string = 1 "sml_errormsg";
- prim_val mkerrno_ : int -> OS.syserror = 1 "identity";
- val errno = errno_ ()
- in
- if errno = 0 then raiseSysML mlOp operand reason
- else raise OS.SysErr
- (formatErr mlOp operand (errormsg_ errno),
- SOME (mkerrno_ errno))
- end
- in
-
- type dirstream = dirstruct_ option ref;
- datatype access = A_READ | A_WRITE | A_EXEC;
-
- fun access (path, perm) =
- let fun mem p = if List.exists (fn q => p=q) perm then 1 else 0
- val permcode = mem A_READ + 2 * mem A_WRITE + 4 * mem A_EXEC
- in
- (access_ path permcode)
- handle Fail s => raiseSys "access" path s
- end;
-
- fun getDir () =
- (getdir_ ())
- handle Fail s => raiseSys "getDir" "" s;
-
- fun isDir p =
- (isdir_ p) handle Fail s => raiseSys "isDir" p s;
-
- fun mkDir p =
- (mkdir_ p) handle Fail s => raiseSys "mkDir" p s;
-
- #ifdef unix
- fun chDir p =
- (chdir_ p)
- handle Io _ => raiseSys "chDir" p "chdir";
-
- fun mosmlRealPath p =
- let prim_val islink_ : string -> bool = 1 "sml_islink"
- prim_val readlink_ : string -> string = 1 "sml_readlink"
- val links = ref 0
- fun incrlink () =
- if !links < 30 then links := !links + 1
- else raise Fail "Too many symbolic links encountered"
- open Path
- fun expand p =
- let val {vol, arcs, isAbs} = Path.fromString p
- val root = if isAbs then vol ^ "/" else vol
- in mkCanonical (List.foldl followlink root arcs) end
- and followlink (a, p) =
- let val file = concat(p, a)
- in
- if islink_ file then
- (incrlink();
- expand(mkAbsolute(readlink_ file, p)))
- else
- file
- end
- in
- (expand(mkAbsolute(p, getDir())))
- handle Fail s => raiseSys "realPath" p s
- end;
-
- fun realPath p =
- let prim_val realpath_ : string -> string = 1 "sml_realpath"
- in
- (realpath_ p)
- handle Fail "realpath not supported" => mosmlRealPath p
- | Fail s => raiseSys "realPath" p s
- end;
-
- fun isLink p =
- let prim_val islink_ : string -> bool = 1 "sml_islink"
- in (islink_ p) handle Fail s => raiseSys "isLink" p s end;
-
- fun readLink p =
- let prim_val readlink_ : string -> string = 1 "sml_readlink"
- in (readlink_ p) handle Fail s => raiseSys "readLink" p s end;
- #endif
- #ifdef msdos
- fun chDir p =
- let prim_val setdisk_ : int -> unit = 1 "sml_setdisk"
- fun failvol () = raiseSys "chDir" p "Illegal volume name"
- fun volno c = (* A = 0, B = 1, ... *)
- if Char.isAlpha c then (Char.ord c - 65) mod 32
- else failvol ()
- val vol = Path.getVolume p
- in
- if vol = "" then ()
- else (setdisk_ (volno (String.sub(vol, 0))))
- handle Fail s => failvol ();
- (chdir_ p) handle Io _ => raiseSys "chDir" p "chdir"
- end;
-
- fun realPath p =
- let open Path
- val realp = mkCanonical(mkAbsolute(p, getDir()))
- in
- if access (realp, []) then realp
- else raise raiseSys "realPath" realp "access"
- end
-
- fun isLink p =
- if access_ p 0 then false
- else raiseSys "isLink" p "No such file";
-
- fun readLink p =
- raiseSys "readLink" p "Irrelevant for DOS";
- #endif
- #ifdef macintosh
- fun chDir p =
- (chdir_ p)
- handle Io _ => raiseSys "chDir" p "chdir";
-
- fun realPath p =
- let prim_val realpath_ : string -> string = 1 "sml_realpath"
- in
- (realpath_ p)
- handle Fail s => raiseSys "realPath" p s
- end;
-
- fun isLink p =
- let prim_val islink_ : string -> bool = 1 "sml_islink"
- in (islink_ p) handle Fail s => raiseSys "isLink" p s end;
-
- fun readLink p =
- let prim_val readlink_ : string -> string = 1 "sml_readlink"
- in (readlink_ p) handle Fail s => raiseSys "readLink" p s end;
- #endif
-
- fun rmDir p =
- (rmdir_ p) handle Fail s => raiseSys "rmDir" p s;
-
- fun tmpName (arg as {dir, prefix}) =
- let val dir' =
- case dir of
- NONE => defaulttempdir
- | SOME path =>
- if access (path,[A_WRITE]) andalso isDir path then path
- else defaulttempdir
- val prefix' =
- case prefix of
- NONE => "tm"
- | SOME p => p (* length prefix <= 2 under DOS *)
- val template = dir' ^ "/" ^ prefix' ^ "XXXXXX"
- in
- (mktemp_ template)
- handle Fail s => raiseSys "tmpName" prefix' s
- end
-
- fun modTime p =
- (Time.realToTime (modtime_ p))
- handle Fail s => raiseSys "modTime" p s;
-
- fun remove p =
- (remove_ p)
- handle Io _ => raiseSys "remove" p "unlink";
-
- fun rename {old, new} =
- (rename_ old new)
- handle Io _ => raiseSys "rename" old "rename";
-
- fun setTime (path, time) =
- let val tsec =
- Time.timeToReal (case time of NONE => Time.now() | SOME t => t)
- in
- (settime_ path tsec)
- handle Fail s => raiseSys "setTime" path s
- end;
-
- fun openDir path =
- (ref (SOME (opendir_ path)))
- handle Fail s => raiseSys "openDir" path s;
-
- fun readDir (ref NONE) =
- raiseSysML "readDir" "" "Directory stream has been closed"
- | readDir (ref (SOME dstr)) = readdir_ dstr;
-
- fun rewindDir (ref NONE) =
- raiseSysML "rewindDir" "" "Directory stream has been closed"
- | rewindDir (ref (SOME dstr)) = rewinddir_ dstr;
-
- fun closeDir (ref NONE) =
- raiseSysML "closeDir" "" "Directory stream is closed already"
- | closeDir (r as ref (SOME dstr)) =
- (r := NONE; closedir_ dstr);
- end;
-